home *** CD-ROM | disk | FTP | other *** search
/ Amiga Games Extra 1996 June / Amiga Games Extra 1996 #6.iso / userbox / publicdomain / splitter / splitter.c < prev    next >
Text File  |  1996-03-05  |  42KB  |  1,659 lines

  1. /*
  2.  
  3.   Splitter 3.02
  4.  
  5.   This program can split files into several portions with a defined
  6.   size or into a defined number of portions and can join them together
  7.   again. It's main purpose is to write larger files and especially
  8.   archives to disks. It was designed to compile under ANSI C and with
  9.   some small modifications even under K&R C, and thus to run on any
  10.   system which supports these.
  11.  
  12.   Version 1.0  on 18-October-1993   First reliable version.
  13.   Version 1.1  on 18-October-1993   Replaced fclose()/fopen() by rewind().
  14.   Version 1.2  on 24-November-1993  Works now with MSDOS systems;
  15.                     uses a buffer for join.
  16.   Version 1.21 on 25-November-1993  Removed a small bug in the output.
  17.   Version 2.0  on 22-September-1994 Added default sizes for filesystems.
  18.                     Uses Buffer for read/write. Uses fileheader
  19.                     for recognition and restauration.
  20.   Version 2.1  on 31-March-1995        Options -r (splitted portion range, only
  21.                     with -p and -s) and -f (force overwrite)
  22.                     added. Bug removed when allocating smaller
  23.                     buffer. Multivolume joining enhanced.
  24.   Version 3.0  on 22-February-1996  Complete rewrite. Enhanced command line
  25.                     parsing. Joining and multivolume via
  26.                     command name.
  27.   Version 3.01 on 27-February-1996  Removed bug in splitpath generation.
  28.   Version 3.02 on 5-March-1996        Removed another small bug in splitpath
  29.                     generation. Cleaned up usage info.
  30.                     Removed bug with empty files.
  31.  
  32.   This program was developed on an Amiga 1200 with the SAS/C development system
  33.   and the GNU emacs editor, the UNIX adaptions were written on a Linux PC with
  34.   gcc and emacs.
  35.  
  36.   Usage:
  37.    Splitter [-n] [-d] [-l] [-m] [-g] [-f] [-q] [-j {<sources>} <destination>]
  38.      [-h] [[-p <n>] [-s <n>[k|m]] [-s <disktype>] [-r <s> [<e>]] <file> <dir>]
  39.  
  40.    Joiner [-h] [-d] [-n] [-m] [-g] [-f] {<sources>} <destination>
  41.  
  42.     file    the file to be splitted.
  43.     dir        directory where to put the splitted parts.
  44.     sources    source directories and files.
  45.     destination destination path for joined file.
  46.     -h        show help.
  47.     -n        write/expect no header.
  48.     -d        MSDOS filename option: eight characters without dot.
  49.     -l        long filenames; resets the MSDOS switch.
  50.     -m        multivolume split/join; pause after each file.
  51.     -g        go ahead; resets the multivolume switch.
  52.     -f        overwrite existing files without asking (force).
  53.     -q        ask before overwriting files (query).
  54.     -j        join splitted parts.
  55.     -p        split into <n> portions.
  56.     -s        split into portions of <n> bytes size each.
  57.     -r        extract only portions in the range from s(tart) to e(nd).
  58.  
  59.   General:
  60.    To get from Splitter, type the option "-h". Without options, Splitter
  61.    will will do the standard action depending on the command name. If the
  62.    command name contains the string "join" or "Join", splitter will react
  63.    as if called with the option "-j". Otherwise it will split <source> to
  64.    portions with the size of the first file system. If the command name
  65.    contains "m" or "M", the multivolume option will be set automatically.
  66.    If Splitter is compiled for a MSDOS platform, the MSDOS option is set.
  67.    If the macro FORCE is defined, files are overwritten by default.
  68.    To compile this program on a UNIX platform, the macro UNIX must be
  69.    defined; for MSDOS computers, the MSDOS macro must be defined; the AMIGA
  70.    macro is normally set by the compiler on the Amiga. The strings in
  71.    the text define section may be changed to another language (or better
  72.    english.. :-). If you do so, please let me have these.
  73.  
  74.   Splitting:
  75.    There are two different approaches to split a file. The one produces
  76.    the requested number of portion files with the same size each. Use
  77.    "-p <n>" as options for this. The other produces several portions of
  78.    the requested size. The size may be given directly in bytes, kbytes
  79.    or mbytes. Use "-s <n>[k|m]" for this. Or it may be given as the
  80.    destination disk type. Use option "-s <disktype>", where disktype may
  81.    be any one of the filesystem sizes as listed by the option "-h". If
  82.    no option is specified, the file is splitted as though <disktype> had
  83.    beed set to the first in the list. <source> ist the path of the source
  84.    file, <dir> is the path of the (optional) destination directory. The
  85.    option "-d" makes the destination filenames msdos compliant. If "-n"
  86.    is given, no header is written, the portions may be joined then by
  87.    AmigaDOS' Join or unix' cat command. "-r <s> [<e>]" extracts only the
  88.    portion <s> or the prtions <s> to <e>. "-m" lets Splitter pause before
  89.    writing each portion so that a removable medium may be changed. If
  90.    "-f" is specified, Splitter overwrites files without asking.
  91.  
  92.   Joining:
  93.    Calling Splitter with a name that contains the word 'join' (i.e. via
  94.    softlink) or with the option "-j" will create the original file from
  95.    the portions. If the destination file name is given, only one source
  96.    directory is required. This and any further source directory is scanned
  97.    for the needed portions, and any source file is checked if it is a
  98.    portion. If the destination is a directory at least one source file
  99.    must be given. The destination file name is then derived from the
  100.    header or from this file's name if no header can be found. The option
  101.    "-d" makes Splitter look for source files with msdos compliant filenames.
  102.    "-m" lets Splitter pause before reading the next directory. The option
  103.    "-f" makes Splitter overwrite files without asking. If "-n" is given,
  104.    Splitter does not look for headers.
  105.  
  106. DISCLAIMER:
  107.   I am in no way responsible for any problems that arise directly or
  108.   indirectly from the use of this program.
  109.  
  110. Copyright notice:
  111.   This is freeware. You may give this program to anyone you like and
  112.   upload it to any mailbox, bulletin board or software server or include
  113.   it on any public domain distribution on disk or on CD-ROM as long as
  114.   you charge only a small fee for medium and copy and leave this file as
  115.   it is. But you may not use this program for commercial purposes without
  116.   prior written permission from me. You may not distribute changed
  117.   versions of this program.
  118.   If you have any ideas how to improve this program, please mail
  119.   them to me. My mail address is included in the info #define.
  120.  
  121. The author:
  122.   I'm a student of computer science at the university of Tuebingen,
  123.   Germany. If you like this program, please let me know. This program
  124.   was intentionally made freeware. If you have written some shareware
  125.   program, be so kind to let me have it for free if you use Splitter
  126.   frequently.
  127.   Please feel free to mail me any ideas concerning this program.
  128.  
  129. My address:
  130.   Martin Schlodder
  131.   Uhlandstr. 18
  132.   D-72336 Balingen
  133.  
  134. EMAIL:
  135.   schlodder@student.uni-tuebingen.de
  136. */
  137.  
  138. /*
  139.   Select the appropriate #define statement or use the define compiler
  140.   option to choose the system on which you want to compile this source.
  141.   These defines are neccessary to select the right path seperators.
  142.   If you know any more file systems, please mail their path rules to
  143.   me and i will include them.
  144. #define AMIGA
  145. #define MSDOS
  146. #define UNIX
  147. */
  148.  
  149. /*
  150.   Some more filesystems for the Amiga may be enabled by the following:
  151. #define AMIFS      Amiga file systems
  152. #define AMIDC      AmigaOS 3.0 DirCache file system
  153. #define AMIPFS     PFS file system
  154. #define AMIDS      DiskSpare device
  155. */
  156.  
  157. /*
  158.   If FORCE is defined, Splitter does not ask before overwriting files
  159.   by default.
  160. #define FORCE
  161. */
  162.  
  163. /*
  164.   If DBUG is defined, each function will print it's arguments.
  165. #define DBUG
  166. */
  167.  
  168. /*
  169.   The following #define block contains every text printed by Splitter.
  170.   The messages are collected to make translation easier.
  171. */
  172. /*
  173.   Info is printed if the -h option is set.
  174. */
  175. #define info1 "\nSplitter V3.02 on March 5, 1996\n\
  176. (c)1993-1996 by Martin Schlodder\n\n"
  177. #define info1s info1 "\
  178. Usage: %s [-n] [-d] [-l] [-m] [-g] [-f] [-q] [-j {<sources>} <destination>]\n\
  179.   [-h] [[-p <n>] [-s <n>[k|m]] [-s <disktype>] [-r <s> [<e>]] <file> <dir>]\n\
  180.  file\t\tthe file to be splitted.\n\
  181.  dir\t\tdirectory where tp put the splitted parts.\n\
  182.  sources\tsource directories and files.\n\
  183.  destination\tdestination path for joined file.\n\
  184.  -h\t\tshow this help page.\n\
  185.  -n\t\twrite/expect no header.\n\
  186.  -d\t\tMSDOS filename option: eight chars without dot.\n\
  187.  -l\t\tlong filenames; resets the MSDOS switch.\n\
  188.  -m\t\tmultivolume split/join; pause after each file.\n\
  189.  -g\t\tgo ahead; resets the multivolume switch.\n\
  190.  -f\t\toverwrite existing files fithout asking (force).\n\
  191.  -q\t\task before overwriting files (query).\n\
  192.  -j\t\tjoin splitted parts.\n\
  193.  -p\t\tsplit into <n> portions.\n\
  194.  -s\t\tsplit into portions of <n> [k|m]bytes size each.\n\
  195.  -r\t\textract only portions in the range from s(tart) to e(end).\n\
  196. If neither -j nor -p nor -s are set, Splitter will create portions of\n\
  197. the size from the first line of the list below.\n\n\
  198. [Press <Return> to continue]"
  199. #define info1j info1 "\
  200. Usage: %s [-h] [-n] [-d] [-l] [-m] [-g] [-f] [-q] {<sources>} <destination>\n\
  201.  sources\tsource directories and files.\n\
  202.  destination\tdestination path for joined file.\n\
  203.  -h\t\tshow this help page.\n\
  204.  -n\t\twrite/expect no header.\n\
  205.  -d\t\tMSDOS filename option: eight chars without dot.\n\
  206.  -l\t\tlong filenames; resets the MSDOS switch.\n\
  207.  -m\t\tmultivolume split/join; pause after each file.\n\
  208.  -g\t\tgo ahead; resets the multivolume switch.\n\
  209.  -f\t\toverwrite existing files fithout asking (force).\n\
  210.  -q\t\task before overwriting files (query).\n"
  211. #define info2 "\nFile system sizes:  (for <disktype>)"
  212. #define main_fs " %-12s - %7d bytes - %s."
  213. #define main_end "\n\
  214. Address:\n\
  215.  Martin Schlodder\n\
  216.  Uhlandstr. 18\n\
  217.  D-72336 Balingen\n\n\
  218. Internet:\n\
  219.  schlodder@zdv.uni-tuebingen.de\n"
  220.  
  221. /*
  222.   This text is shown before waiting for a key press when the -w option is set.
  223. */
  224. #define make_multi_part "Please insert volume and press <Return>"
  225.  
  226. /*
  227.   This text is shown when a file will be overwritten and the -q option is set.
  228.   The key definition is the positive answer (overwrite).
  229. */
  230. #define query_overwrite_a "Overwrite file \"%s\"? [y(es)|n(o)|a(ll)] "
  231. #define query_overwrite "Overwrite file \"%s\"? [y(es)|n(o)] "
  232. #define query_yes 'y'
  233. #define query_all 'a'
  234.  
  235. /*
  236.   These texts are used to print the success message after joining.
  237. */
  238. #define join_heads "Headers found."
  239. #define join_Joined "Joined \"%s\""
  240. #define join_file ", \"%s\""
  241. #define join_to " to \"%s\"."
  242. #define multi_join "Joined one portion to \"%s\"."
  243. #define multi_join_n "Joined %d portions to \"%s\"."
  244.  
  245. /*
  246.   These texts are used to print the success message after splitting.
  247. */
  248. #define split_Splitted "Splitted \"%s\" into "
  249. #define split_portion "one portion of %d bytes."
  250. #define split_portions "%d portions of %d bytes."
  251. #define split_portion_and "one portion of %d bytes and\none portion of %d bytes."
  252. #define split_portions_and "%d portions of %d bytes and\none portion of %d bytes."
  253. #define split_Extract "Extracted portions %d to %d."
  254. #define split_Extract_one "Extracted portion %d."
  255.  
  256. /*
  257.   These are the error messages.
  258. */
  259. #define err_bad_dest "Destination must be a directory."
  260. #define err_bad_file "Bad file name definition."
  261. #define err_bad_files "No portions found."
  262. #define err_bad_num "Bad number specification for option '-p'."
  263. #define err_bad_range "Range parameters illegal."
  264. #define err_bad_size "Bad size specification for option '-s'."
  265. #define err_file_empty "Source file is empty."
  266. #define err_no_args "Need a file name to split. Type '%s -h' for help."
  267. #define err_no_file "Need a file name."
  268. #define err_no_files "Destination path or portion paths must contain a filename."
  269. #define err_no_mem "Not enough memory."
  270. #define err_no_name "The source files must have a splitter format name\nif joining portions without header."
  271. #define err_no_portion "Can't find any files to join."
  272. #define err_no_source "Need a source directory or source files to join."
  273. #define err_open_dest "Couldn't open \"%s\" as destination."
  274. #define err_open_dir "Could't read directory \"%s\"."
  275. #define err_open_source "Couldn't open \"%s\" as source."
  276. #define err_portion_missing "Can't find portion %d."
  277. #define err_read "Error while reading."
  278. #define err_read_head "Error while reading header."
  279. #define err_seek "Error while seeking file."
  280. #define err_unknown_option "Unknown option '-%c'."
  281. #define err_write "Error while writing."
  282. #define err_write_abort "File not overwritten. Execution aborted."
  283. #define err_write_head "Error while writing header."
  284. #define err_wrong_portion "Portion number differs from header number."
  285.  
  286. /*
  287.   These are the warning messages.
  288. */
  289. #define warn_size "WARNING! Source file size changed."
  290. #define warn_t_size "WARNING! Destination file size changed."
  291. #define warn_files_missing "WARNING! Some portions are missing."
  292. #define warn_n_files_missing "WARNING! %d portions are missing."
  293. #define warn_one_file_missing "WARNING! One portion is missing."
  294. #define warn_wrong_portion "WARNING! Wrong portion in source file list."
  295.  
  296. /*
  297.   These are the known file systems.
  298. */
  299. struct fs_item
  300. {
  301.   char *name;
  302.   unsigned long size;
  303.   char *desc;
  304. }fs[]={
  305.   {"msd-dd",730112,"MSDOS Double Density Disk"},
  306.   {"msd-hd",1457664,"MSDOS High Density Disk"},
  307. #ifdef AMIFS
  308.   {"amiofs-dd",844240,"Amiga Double Density Disk, OldFileSystem"},
  309.   {"amiofs-hd",1691408,"Amiga High Density Disk, OldFileSystem"},
  310.   {"amiffs-dd",885760,"Amiga Double Density Disk, FastFileSystem"},
  311.   {"amiffs-hd",1774592,"Amiga High Density Disk, FastFileSystem"},
  312. #ifdef AMIDC
  313.   {"amiofsdc-dd",843752,"Amiga Double Density Disk, OldFileSystem, DirCache"},
  314.   {"amiofsdc-hd",1690920,"Amiga High Density Disk, OldFileSystem, DirCache"},
  315.   {"amiffsdc-dd",884736,"Amiga Double Density Disk, FastFileSystem, DirCache"},
  316.   {"amiffsdc-hd",1774080,"Amiga High Density Disk, FastFileSystem, DirCache"},
  317. #endif
  318. #ifdef AMIPFS
  319.   {"amipfs-dd",896512,"Amiga Double Density Disk, ProfFileSystem"},
  320.   {"amipfs-hd",1797632,"Amiga High Density Disk, ProfFileSystem"},
  321. #endif
  322. #ifdef AMIDS
  323.   {"amidsofs-dd",844240,"Amiga Double Density Disk, DiskSpare, OldFileSystem"},
  324.   {"amidsofs-hd",1691408,"Amiga High Density Disk, DiskSpare, OldFileSystem"},
  325.   {"amidsffs-dd",885760,"Amiga Double Density Disk, DiskSpare, FastFileSystem"},
  326.   {"amidsffs-hd",1774592,"Amiga High Density Disk, DiskSpare, FastFileSystem"},
  327. #ifdef AMIDC
  328.   {"amidsofsdc-dd",843752,"Amiga Double Density Disk, DiskSpare, OldFileSystem, DirCache"},
  329.   {"amidsofsdc-hd",1690920,"Amiga High Density Disk, DiskSpare, OldFileSystem, DirCache"},
  330.   {"amidsffsdc-dd",884736,"Amiga Double Density Disk, DiskSpare, FastFileSystem, DirCache"},
  331.   {"amidsffsdc-hd",1774080,"Amiga High Density Disk, DiskSpare, FastFileSystem, DirCache"},
  332. #endif
  333. #ifdef AMIPFS
  334.   {"amidspfs-dd",1003008,"Amiga Double Density Disk, DiskSpare, ProfFileSystem"},
  335.   {"amidspfs-hd",2010624,"Amiga High Density Disk, DiskSpare, ProfFileSystem"},
  336. #endif
  337. #endif
  338. #endif
  339. };
  340.  
  341. /*
  342.   The maximal length of an input string:
  343. */
  344. #define STRMAX 256
  345.  
  346. /*
  347.   Standard includes.
  348. */
  349. #include <stdlib.h>
  350. #include <stdio.h>
  351. #include <string.h>
  352. #include <ctype.h>
  353. #include <dirent.h>
  354.  
  355. /*
  356.   Each file is preceded with a fileheader (if the -n option was not set)
  357.   consisting of the following structure:
  358. */
  359. #define hd_magic "Splitter"
  360. #define hd_name (8+4+8+4+8+1)
  361. #define hd_namesize 31
  362. struct header{
  363.   short number;
  364.   unsigned long size;
  365.   short tnumber;
  366.   unsigned long tsize;
  367.   char name[hd_namesize];
  368. };
  369. #define hd_size (hd_name+hd_namesize) 
  370.  
  371. /*
  372.   This is the version information for the Amiga's shell command 'Version'.
  373. */
  374. #ifdef AMIGA
  375. char *amiga_version="$VER: Splitter 3.02 (5.3.96)   ©1993-1996 by Martin Schlodder";
  376. #endif
  377.  
  378. /*
  379.   The only global variables are some status flags, the range parameters
  380.   and a string buffer.
  381. */
  382. int rstart,rend,msdos,head,multi,query;
  383. char buf[STRMAX];
  384.  
  385. /*
  386.   int WriteHead(FILE *fh,header *hd)
  387.     fh:       File handle.
  388.     hd:       Pointer to header structure.
  389.     returns:  Nonzero if error occurs.
  390.   This function writes the header from the the structure hd into the file fh. 
  391. */
  392. int WriteHead(FILE *fh,struct header *hd){
  393.   char hdbuf[hd_size];
  394. #ifdef DBUG
  395.   printf("\nWriteHead($%08X,{%d,%lu,%d,%lu,\"%s\"});\n",fh,hd->number,hd->size,hd->tnumber,hd->tsize,hd->name);
  396. #endif
  397.   sprintf(hdbuf,"%s%4X%8X%4X%8X ",hd_magic,hd->number,hd->size,hd->tnumber,hd->tsize);
  398.   memcpy(hdbuf+hd_name,hd->name,hd_namesize);
  399.   if(fwrite(hdbuf,1,hd_size,fh)!=hd_size)
  400.     return(1);
  401.   return(0);
  402. }
  403.  
  404. /*
  405.   int ReadHead(FILE *fh,header *hd)
  406.     fh:       File handle.
  407.     hd:       Pointer to header structure.
  408.     returns:  Nonzero if error occurs.
  409.   This function reads the header from the file fh into the structure hd.
  410. */
  411. int ReadHead(FILE *fh,struct header *hd){
  412.   char buf[hd_size];
  413. #ifdef DBUG
  414.   printf("\nReadHead($%x,$%x);\n",fh,hd);
  415. #endif
  416.   if(fread(buf,1,hd_size,fh)!=hd_size){
  417. #ifdef DBUG
  418.     puts("\nReadHead() -> 1");
  419. #endif
  420.     return(1);
  421.   }
  422.   if(4!=sscanf(buf,hd_magic "%4hx%8lx%4hx%8lx ",&hd->number,&hd->size,&hd->tnumber,&hd->tsize)){
  423. #ifdef DBUG
  424.     puts("\nReadHead() -> 1");
  425. #endif
  426.     return(1);
  427.   }
  428.   memcpy(hd->name,buf+hd_name,hd_namesize);
  429. #ifdef DBUG
  430.   printf("\nReadHead() -> 0   hd: {%d,%lu,%d,%lu,\"%s\"}\n",hd->number,hd->size,hd->tnumber,hd->tsize,hd->name);
  431. #endif
  432.   return(0);
  433. }
  434.  
  435. /*
  436.   Join(char *dest,char *paths[],int num)
  437.     dest:     Destination path or empty string.
  438.     paths:    Array of source paths.
  439.     num:      Number of source paths.
  440.   Global:
  441.     msdos:    -use-  Filenames of portions are supposed to be MSDOS
  442.                      compatible (eight characters, no dots).
  443.     head:     -use-  Try to find header.
  444.     query:    -use-  Ask before overwriting existing files.
  445.     multi:    -use-  Join from multiple volumes using MultiJoin().
  446.   Calls:
  447.     ReadHead: Read header from portion file.
  448.   Join() joins the portions to the original file. Dest is a directory or
  449.   file, paths is NULL if num is 0. Frees 'paths' allocated by main().
  450. */
  451. void Join(char *dest,char **paths,int num){
  452.   int i,j,k,fnum,dnum,dir,tnum,chunks;
  453.   unsigned long tsize,size,asize,read,written,twritten;
  454.   int *isdir,*findex,*jindex;
  455.   char *sbuf,*tbuf,*dfile,*pos,*name;
  456.   char **sfiles,**files, **dirs;
  457.   FILE *source,*dhand;
  458.   DIR *dfd;
  459.   struct header hd;
  460. #ifdef DBUG
  461.   printf("\nJoin(\"%s\",({",dest);
  462.   for(i=0;i<num-1;i++)
  463.     printf("\"%s\",",paths[i]);
  464.   if(num)
  465.     printf("\"%s\"",paths[i]);
  466.   printf("}),%d);   Uses: multi(%s), head(%s), query(%s), msdos(%s)\n",num,multi?"TRUE":"FALSE",head?"TRUE":"FALSE",query?"TRUE":"FALSE",msdos?"TRUE":"FALSE");
  467. #endif
  468.   dir=0;
  469.   if(!num){
  470.     puts(err_no_source);
  471.     free(paths);
  472.     exit(EXIT_FAILURE);
  473.   }
  474.   if(dfd=opendir(dest)){
  475.     closedir(dfd);
  476.     dir=1;
  477.   }
  478.   if(!(isdir=(int *)malloc(num*sizeof(int)))){
  479.     puts(err_no_mem);
  480.     free(paths);
  481.     exit(EXIT_FAILURE);
  482.   }
  483.   for(i=dnum=0;i<num;i++)
  484.     if(dfd=opendir(paths[i])){
  485.       closedir(dfd);
  486.       isdir[i]=1;
  487.       dnum++;
  488.     }
  489.     else
  490.       isdir[i]=0;
  491.   fnum=num-dnum;
  492.   files=dirs=0;
  493.   if(dnum && !(dirs=(char **)malloc(dnum*sizeof(char *)))){
  494.     puts(err_no_mem);
  495.     free(paths);
  496.     free(isdir);
  497.     exit(EXIT_FAILURE);
  498.   }
  499.   if(fnum && !(files=(char **)malloc(fnum*sizeof(char *)))){
  500.     puts(err_no_mem);
  501.     free(paths);
  502.     free(isdir);
  503.     free(dirs);
  504.     exit(EXIT_FAILURE);
  505.   }
  506.   for(i=dnum=fnum=0;i<num;i++)
  507.     if(isdir[i])
  508.       dirs[dnum++]=paths[i];
  509.     else
  510.       files[fnum++]=paths[i];
  511.   free(paths);
  512.   free(isdir);
  513.   size=0;
  514.   tnum=0;
  515.   if(fnum){
  516.     if(!(findex=(int *)malloc(fnum*sizeof(int)))){
  517.       puts(err_no_mem);
  518.       free(files);
  519.       if(dnum)
  520.     free(dirs);
  521.       exit(EXIT_FAILURE);
  522.     }
  523.     if(!(source=fopen(files[0],"rb"))){
  524.       printf(err_open_source "\n",files[0]);
  525.       free(findex);
  526.       free(files);
  527.       if(dnum)
  528.     free(dirs);
  529.       exit(EXIT_FAILURE);
  530.     }
  531.     if(head && ReadHead(source,&hd))
  532.       head=0;
  533.     if(head){
  534.       size=hd.size>size?hd.size:size;
  535.       findex[0]=hd.number;
  536.     }
  537.     else{
  538.       if(fseek(source,0L,SEEK_END)){
  539.     puts(err_seek);
  540.     fclose(source);
  541.     free(findex);
  542.     free(files);
  543.     if(dnum)
  544.       free(dirs);
  545.     exit(EXIT_FAILURE);
  546.       }
  547.       size=(asize=ftell(source))>size?asize:size;
  548.     }
  549.     fclose(source);
  550.     for(i=1;i<fnum;i++){
  551.       if(!(source=fopen(files[i],"rb"))){
  552.     printf(err_open_source "\n",files[i]);
  553.     free(findex);
  554.     free(files);
  555.     if(dnum)
  556.       free(dirs);
  557.     exit(EXIT_FAILURE);
  558.       }
  559.       if(head){
  560.     if(ReadHead(source,&hd)){
  561.       puts(err_read_head);
  562.       fclose(source);
  563.       free(findex);
  564.       free(files);
  565.       if(dnum)
  566.         free(dirs);
  567.       exit(EXIT_FAILURE);
  568.     }
  569.     size=hd.size>size?hd.size:size;
  570.     findex[i]=hd.number;
  571.       }
  572.       else{
  573.     if(fseek(source,0L,SEEK_END)){
  574.       puts(err_seek);
  575.       fclose(source);
  576.       free(findex);
  577.       free(files);
  578.       if(dnum)
  579.         free(dirs);
  580.       exit(EXIT_FAILURE);
  581.     }
  582.     size=(asize=ftell(source))>size?asize:size;
  583.       }
  584.       fclose(source);
  585.     }
  586.     if(head){
  587.       tnum=hd.tnumber;
  588.       tsize=hd.tsize;
  589.     }
  590.     else{
  591.       for(i=0;i<fnum;i++)
  592.     tnum=(findex[i]=atoi(files[i]+strlen(files[i])-3))>tnum?findex[i]:tnum;
  593.     }
  594.     if(!(jindex=(int *)calloc(tnum,sizeof(int)))){
  595.       puts(err_no_mem);
  596.       free(findex);
  597.       free(files);
  598.       if(dnum)
  599.     free(dirs);
  600.       exit(EXIT_FAILURE);
  601.     }
  602.     for(i=0;i<tnum;i++)
  603.       for(j=0;j<fnum;j++)
  604.     if(findex[j]==i+1){
  605.       jindex[i]=j+1;
  606.       break;
  607.     }
  608.     free(findex);
  609.     if(dir){
  610. #ifndef UNIX
  611.       if(i=strlen(dest)){
  612. #ifdef AMIGA
  613.     if(dest[--i]=='/' || dest[i]==':')
  614.       j=0;
  615. #else
  616.     if(dest[--i]=='\\' || dest[i]==':')
  617.       j=0;
  618. #endif
  619.     else
  620.       j=1;
  621.       }
  622.       else
  623.     j=0;
  624.       if(head){
  625.     if(!(dfile=(char *)malloc(strlen(hd.name)+strlen(dest)+j+1))){
  626.       puts(err_no_mem);
  627.       free(jindex);
  628.       free(files);
  629.       if(dnum)
  630.         free(dirs);
  631.       exit(EXIT_FAILURE);
  632.     }
  633. #ifdef AMIGA
  634.     sprintf(dfile,"%s%s%s",dest,j?"/":"",hd.name);
  635. #else
  636.     sprintf(dfile,"%s%s%s",dest,j?"\\":"",hd.name);
  637. #endif
  638.       }
  639.       else{
  640. #ifdef AMIGA
  641.     if(!(pos=strrchr(files[0],'/')) && !(pos=strrchr(files[0],':')))
  642.       pos=files[0];
  643. #else
  644.     if(!(pos=strrchr(files[0],'\\')) && !(pos=strrchr(files[0],':')))
  645.       pos=files[0];
  646. #endif
  647.     if(!(dfile=(char *)malloc(strlen(pos)+strlen(dest)+j-3))){
  648.       puts(err_no_mem);
  649.       free(jindex);
  650.       free(files);
  651.       if(dnum)
  652.         free(dirs);
  653.       exit(EXIT_FAILURE);
  654.     }
  655. #ifdef AMIGA
  656.     sprintf(dfile,"%s%s%.*s",dest,j?"/":"",strlen(pos)-4,pos);
  657. #else
  658.     sprintf(dfile,"%s%s%.*s",dest,j?"\\":"",strlen(pos)-4,pos);
  659. #endif
  660.       }
  661. #else
  662.       if(head){
  663.     if(!(dfile=(char *)malloc(strlen(hd.name)+strlen(dest)+1))){
  664.       puts(err_no_mem);
  665.       free(jindex);
  666.       free(files);
  667.       if(dnum)
  668.         free(dirs);
  669.       exit(EXIT_FAILURE);
  670.     }
  671.     sprintf(dfile,"%s/%s",dest,hd.name);
  672.       }
  673.       else{
  674.     if(!(pos=strrchr(files[0],'/')))
  675.       pos=files[0];
  676.     if(!(dfile=(char *)malloc(strlen(pos)+strlen(dest)-3))){
  677.       puts(err_no_mem);
  678.       free(jindex);
  679.       free(files);
  680.       if(dnum)
  681.         free(dirs);
  682.       exit(EXIT_FAILURE);
  683.     }
  684.     sprintf(dfile,"%s/%.*s",dest,strlen(pos)-4,pos);
  685.       }
  686. #endif
  687.     }
  688.     else
  689.       dfile=dest;
  690.   }
  691.   else{
  692.     if(dir){
  693.       puts(err_no_files);
  694.       free(dirs);
  695.       exit(EXIT_FAILURE);
  696.     }
  697.     dfile=dest;
  698.   }
  699.   if(query && (dhand=fopen(dfile,"rb"))){
  700.     fclose(dhand);
  701.     printf(query_overwrite,dfile);
  702.     gets(buf);
  703.     if(buf[0]!=query_yes){
  704.       puts(err_write_abort);
  705.       if(fnum){
  706.     free(jindex);
  707.     free(files);
  708.       }
  709.       if(dnum)
  710.     free(dirs);
  711.       exit(EXIT_FAILURE);
  712.     }
  713.   }
  714.   if(fnum && head){
  715.     if(!(name=(char *)malloc(strlen(hd.name)+1))){
  716.       puts(err_no_mem);
  717.       free(jindex);
  718.       free(files);
  719.       if(dnum)
  720.     free(dirs);
  721.       if(dir)
  722.     free(dfile);
  723.       exit(EXIT_FAILURE);
  724.     }
  725.     strcpy(name,hd.name);
  726.   }
  727.   else{
  728. #ifdef AMIGA
  729.     if((pos=strrchr(dfile,'/')) || (pos=strrchr(dfile,':')))
  730.       pos++;
  731. #endif
  732. #ifdef MSDOS
  733.     if((pos=strrchr(dfile,'\\')) || (pos=strrchr(dfile,':')))
  734.       pos++;
  735. #endif
  736. #ifdef UNIX
  737.     if(pos=strrchr(dfile,'/'))
  738.       pos++;
  739. #endif
  740.     else
  741.       pos=dfile;
  742.     if(!(name=(char *)malloc(strlen(pos)+1))){
  743.       puts(err_no_mem);
  744.       if(fnum){
  745.     free(jindex);
  746.     free(files);
  747.       }
  748.       if(dnum)
  749.     free(dirs);
  750.       if(dir)
  751.     free(dfile);
  752.       exit(EXIT_FAILURE);
  753.     }
  754.     strcpy(name,pos);
  755.   }
  756.   if(msdos){
  757.     if(pos=strchr(name,'.'))
  758.       pos[0]='\0';
  759.     if(strlen(name)>8)
  760.       name[8]='\0';
  761.   }
  762.   if(dnum){
  763.     if(!(sfiles=(char **)malloc(dnum*sizeof(char *)))){
  764.       puts(err_no_mem);
  765.       free(name);
  766.       if(fnum){
  767.     free(jindex);
  768.     free(files);
  769.       }
  770.       free(dirs);
  771.       if(dir)
  772.     free(dfile);
  773.       exit(EXIT_FAILURE);
  774.     }
  775.     for(i=0;i<dnum;i++){
  776. #ifndef UNIX
  777.       if(k=strlen(dirs[i])){
  778. #ifdef AMIGA
  779.     if(dirs[i][--k]=='/' || dirs[i][k]==':')
  780.       j=0;
  781. #else
  782.     if(dirs[i][--k]=='\\' || dirs[i][k]==':')
  783.       j=0;
  784. #endif
  785.     else
  786.       j=1;
  787.       }
  788.       else
  789.     j=0;
  790.       if(!(sfiles[i]=(char *)malloc(strlen(dirs[i])+j+strlen(name)+1))){
  791.     puts(err_no_mem);
  792.     free(name);
  793.     for(j=0;j<i;j++)
  794.       free(sfiles[j]);
  795.     free(sfiles);
  796.     if(fnum){
  797.       free(jindex);
  798.       free(files);
  799.     }
  800.     free(dirs);
  801.     if(dir)
  802.       free(dfile);
  803.     exit(EXIT_FAILURE);
  804.       }
  805. #ifdef AMIGA
  806.       sprintf(sfiles[i],"%s%s%s",dirs[i],j?"/":"",name);
  807. #else
  808.       sprintf(sfiles[i],"%s%s%s",dirs[i],j?"\\":"",name);
  809. #endif
  810. #else
  811.       if(!(sfiles[i]=(char *)malloc(strlen(dirs[i])+strlen(name)+2))){
  812.     puts(err_no_mem);
  813.     free(name);
  814.     for(j=0;j<i;j++)
  815.       free(sfiles[j]);
  816.     free(sfiles);
  817.     if(fnum){
  818.       free(jindex);
  819.       free(files);
  820.     }
  821.     free(dirs);
  822.     if(dir)
  823.       free(dfile);
  824.     exit(EXIT_FAILURE);
  825.       }
  826.       sprintf(sfiles[i],"%s/%s",dirs[i],name);
  827. #endif
  828.     }
  829.     free(dirs);
  830.   }
  831.   if(!fnum){
  832.     if(multi){
  833.       puts(make_multi_part);
  834.       gets(buf);
  835.     }
  836.     for(i=0;i<dnum;i++){
  837.       if(!(sbuf=malloc(strlen(sfiles[i])+5))){
  838.     puts(err_no_mem);
  839.     free(name);
  840.     for(i=0;i<dnum;i++)
  841.       free(sfiles[i]);
  842.     free(sfiles);
  843.     exit(EXIT_FAILURE);
  844.       }
  845.       sprintf(sbuf,"%s.001",sfiles[i]);
  846.       if(source=fopen(sbuf,"rb"))
  847.     break;
  848.       free(sbuf);
  849.     }
  850.     free(sbuf);
  851.     if(!source){
  852.       puts(err_no_portion);
  853.       free(name);
  854.       for(i=0;i<dnum;i++)
  855.     free(sfiles[i]);
  856.       free(sfiles);
  857.       exit(EXIT_FAILURE);
  858.     }
  859.     if(head && ReadHead(source,&hd))
  860.       head=0;
  861.     if(head){
  862.       tnum=hd.tnumber;
  863.       tsize=hd.tsize;
  864.       size=hd.size;
  865.     }
  866.     else{
  867.       tnum=1;
  868.       if(fseek(source,0L,SEEK_END)){
  869.     puts(err_seek);
  870.     fclose(source);
  871.     free(name);
  872.     for(i=0;i<dnum;i++)
  873.       free(sfiles[i]);
  874.     free(sfiles);
  875.     exit(EXIT_FAILURE);
  876.       }
  877.       size=ftell(source);
  878.     }
  879.     fclose(source);
  880.   }
  881.   if(!(dhand=fopen(dfile,"wb"))){
  882.     printf(err_open_dest "\n",dfile);
  883.     free(name);
  884.     if(dnum){
  885.       for(i=0;i<dnum;i++)
  886.     free(sfiles[i]);
  887.       free(sfiles);
  888.     }
  889.     if(fnum){
  890.       free(jindex);
  891.       free(files);
  892.     }
  893.     if(dir)
  894.       free(dfile);
  895.     exit(EXIT_FAILURE);
  896.   }
  897.   if(!size){
  898.     puts(err_file_empty);
  899.     free(name);
  900.     if(dnum){
  901.       for(i=0;i<dnum;i++)
  902.     free(sfiles[i]);
  903.       free(sfiles);
  904.     }
  905.     if(fnum){
  906.       free(jindex);
  907.       free(files);
  908.     }
  909.     if(dir)
  910.       free(dfile);
  911.     exit(EXIT_FAILURE);
  912.   }
  913.   if(!(tbuf=(char *)malloc(asize=size))){
  914.     while(asize>10000 && !tbuf)
  915.       tbuf=(char *)malloc(asize=(asize+1)/2);
  916.     if(!tbuf){
  917.       puts(err_no_mem);
  918.       fclose(dhand);
  919.       free(name);
  920.       if(dnum){
  921.     for(i=0;i<dnum;i++)
  922.       free(sfiles[i]);
  923.     free(sfiles);
  924.       }
  925.       if(fnum){
  926.     free(jindex);
  927.     free(files);
  928.       }
  929.       if(dir)
  930.     free(dfile);
  931.       exit(EXIT_FAILURE);
  932.     }
  933.   }
  934.   chunks=(size+asize-1)/asize;
  935.   if(!multi && head)
  936.     puts(join_heads);
  937.   for(i=0,twritten=0;!head||i<tnum;i++){
  938.     if(fnum && i<tnum && (j=jindex[i])>0){
  939.       if(!(source=fopen(files[j-1],"rb"))){
  940.     printf(err_open_source "\n",files[j-1]);
  941.     fclose(source);
  942.     fclose(dhand);
  943.     free(tbuf);
  944.     free(name);
  945.     if(dnum){
  946.       for(i=0;i<dnum;i++)
  947.         free(sfiles[i]);
  948.       free(sfiles);
  949.     }
  950.     free(jindex);
  951.     free(files);
  952.     if(dir)
  953.       free(dfile);
  954.     exit(EXIT_FAILURE);
  955.       }
  956.       if(!multi)
  957.     if(i)
  958.       printf(join_file,files[j-1]);
  959.     else
  960.       printf(join_Joined,files[j-1]);
  961.       if(head && ReadHead(source,&hd)){
  962.     puts(err_read_head);
  963.     fclose(source);
  964.     fclose(dhand);
  965.     free(tbuf);
  966.     free(name);
  967.     if(dnum){
  968.       for(i=0;i<dnum;i++)
  969.         free(sfiles[i]);
  970.       free(sfiles);
  971.     }
  972.     free(jindex);
  973.     free(files);
  974.     if(dir)
  975.       free(dfile);
  976.     exit(EXIT_FAILURE);
  977.       }
  978.     }
  979.     else{
  980.       if(!dnum){
  981.     if(!head && i>=tnum)
  982.       break;
  983.     printf("\n" err_portion_missing "\n",i+1);
  984.     fclose(dhand);
  985.     free(tbuf);
  986.     free(name);
  987.     free(jindex);
  988.     free(files);
  989.     if(dir)
  990.       free(dfile);
  991.     exit(EXIT_FAILURE);
  992.       }
  993.       if(multi && (i||fnum)){
  994.     puts(make_multi_part);
  995.     gets(buf);
  996.       }
  997.       for(j=0;j<dnum;j++){
  998.     if(!(sbuf=malloc(strlen(sfiles[j])+5))){
  999.       puts(err_no_mem);
  1000.       fclose(dhand);
  1001.       free(tbuf);
  1002.       free(name);
  1003.       for(i=0;i<dnum;i++)
  1004.         free(sfiles[i]);
  1005.       free(sfiles);
  1006.       if(fnum){
  1007.         free(jindex);
  1008.         free(files);
  1009.       }
  1010.       if(dir)
  1011.         free(dfile);
  1012.       exit(EXIT_FAILURE);
  1013.     }
  1014.     sprintf(sbuf,"%s.%03d",sfiles[j],i+1);
  1015.     if(source=fopen(sbuf,"rb"))
  1016.       break;
  1017.     free(sbuf);
  1018.       }
  1019.       if(source && !multi)
  1020.     if(i)
  1021.       printf(join_file,sbuf);
  1022.     else
  1023.       printf(join_Joined,sbuf);
  1024.       free(sbuf);
  1025.       if(!source){
  1026.     if(!head && i>=tnum)
  1027.       break;
  1028.     printf("\n" err_portion_missing "\n",i+1);
  1029.     fclose(dhand);
  1030.     free(tbuf);
  1031.     free(name);
  1032.     for(i=0;i<dnum;i++)
  1033.       free(sfiles[i]);
  1034.     free(sfiles);
  1035.     if(fnum){
  1036.       free(jindex);
  1037.       free(files);
  1038.     }
  1039.     if(dir)
  1040.       free(dfile);
  1041.     exit(EXIT_FAILURE);
  1042.       }
  1043.       if(head && ReadHead(source,&hd)){
  1044.     puts(err_read_head);
  1045.     fclose(source);
  1046.     fclose(dhand);
  1047.     free(tbuf);
  1048.     free(name);
  1049.     for(i=0;i<dnum;i++)
  1050.       free(sfiles[i]);
  1051.     free(sfiles);
  1052.     if(fnum){
  1053.       free(jindex);
  1054.       free(files);
  1055.     }
  1056.     if(dir)
  1057.       free(dfile);
  1058.     exit(EXIT_FAILURE);
  1059.       }
  1060.     }
  1061.     if(head && hd.number!=i+1){
  1062.       puts(err_wrong_portion);
  1063.       fclose(source);
  1064.       fclose(dhand);
  1065.       free(tbuf);
  1066.       free(name);
  1067.       if(dnum){
  1068.     for(i=0;i<dnum;i++)
  1069.       free(sfiles[i]);
  1070.     free(sfiles);
  1071.       }
  1072.       if(fnum){
  1073.     free(jindex);
  1074.     free(files);
  1075.       }
  1076.       if(dir)
  1077.     free(dfile);
  1078.       exit(EXIT_FAILURE);
  1079.     }
  1080.     for(j=0,written=0;j<chunks;j++){
  1081.       if(!(read=fread(tbuf,1,asize,source))){
  1082.     puts(err_read);
  1083.     fclose(source);
  1084.     fclose(dhand);
  1085.     free(tbuf);
  1086.     free(name);
  1087.     if(dnum){
  1088.       for(i=0;i<dnum;i++)
  1089.         free(sfiles[i]);
  1090.       free(sfiles);
  1091.     }
  1092.     if(fnum){
  1093.       free(jindex);
  1094.       free(files);
  1095.     }
  1096.     if(dir)
  1097.       free(dfile);
  1098.     exit(EXIT_FAILURE);
  1099.       }
  1100.       if(fwrite(tbuf,1,read,dhand)!=read){
  1101.     puts(err_write);
  1102.     fclose(source);
  1103.     fclose(dhand);
  1104.     free(tbuf);
  1105.     free(name);
  1106.     if(dnum){
  1107.       for(i=0;i<dnum;i++)
  1108.         free(sfiles[i]);
  1109.       free(sfiles);
  1110.     }
  1111.     if(fnum){
  1112.       free(jindex);
  1113.       free(files);
  1114.     }
  1115.     if(dir)
  1116.       free(dfile);
  1117.     exit(EXIT_FAILURE);
  1118.       }
  1119.       written+=read;
  1120.     }
  1121.     twritten+=written;
  1122.     fclose(source);
  1123.     if(head && hd.size!=written)
  1124.       puts(warn_size);
  1125.   }
  1126.   fclose(dhand);
  1127.   free(tbuf);
  1128.   free(name);
  1129.   if(dnum){
  1130.     for(j=0;j<dnum;j++)
  1131.       free(sfiles[j]);
  1132.     free(sfiles);
  1133.   }
  1134.   if(fnum){
  1135.     free(jindex);
  1136.     free(files);
  1137.   }
  1138.   if(multi){
  1139.     if(i-1)
  1140.       printf(multi_join_n "\n",i,dfile);
  1141.     else
  1142.       printf(multi_join "\n",dfile);
  1143.   }
  1144.   else
  1145.     printf(join_to "\n",dfile);
  1146.   if(dir)
  1147.     free(dfile);
  1148.   if(head){
  1149.     if(multi)
  1150.       puts(join_heads);
  1151.     if(twritten!=tsize)
  1152.       puts(warn_t_size);
  1153.   }
  1154.   exit(0);
  1155. }
  1156.  
  1157. /*
  1158.   Split(char *file,char *path,int num,unsigned long size)
  1159.     file:     Source file.
  1160.     path:     Destination path.
  1161.     num:      Number of portions. Mutually exclusive with size.
  1162.     size:     Size of the portions. Mutually exclusive with num.
  1163.   Global:
  1164.     rstart:   -use-  First protion to extract.
  1165.     rend:     -use-  Last Portion to extract.
  1166.     msdos:    -use-  Filenames of portions are made MSDOS compatible (eight
  1167.                      characters, no dots).
  1168.     head:     -use-  Write header.
  1169.     multi:    -use-  Split to multiple volumes, waiting after each portion.
  1170.     query:    -use-  Ask before overwriting existing files.
  1171.   Calls:
  1172.     WriteHead:  Write header to portion file.
  1173.   This function does the splitting. If Splitter was called with the -p
  1174.   command set, num is provided. If the -s command or no command was set
  1175.   (default size), size will be valid. file is always valid, path may be
  1176.   NULL.
  1177. */
  1178. void Split(char *file,char *path,int num,unsigned long size){
  1179.   int i,j,cnum;
  1180.   unsigned long tsize,csize,asize,rsize,rcsize,acsize;
  1181.   char *dfile,*dpath,*dbuf,*tbuf,*pos,*name;
  1182.   struct header hd;
  1183.   FILE *source,*dest;
  1184.   DIR *dfd;
  1185. #ifdef DBUG
  1186.   printf("\nSplit(\"%s\",",file);
  1187.   if(path)
  1188.     printf("\"%s\",",path);
  1189.   else
  1190.     printf("0,");
  1191.   printf("%d,%lu);   Uses: rstart(%d), rend(%d), msdos(%s), head(%s), multi(%s), query(%s)\n",num,size,rstart,rend,msdos?"TRUE":"FALSE",head?"TRUE":"FALSE",multi?"TRUE":"FALSE",query?"TRUE":"FALSE");
  1192. #endif
  1193.   if(head){
  1194.     if(size)
  1195.       size=size-hd_size;
  1196.     for(i=0;i<hd_namesize;i++)
  1197.       hd.name[i]='\0';
  1198.   }
  1199.   if(dfd=opendir(file)){
  1200.     closedir(dfd);
  1201.     printf(err_open_source "\n",file);
  1202.     exit(EXIT_FAILURE);
  1203.   }
  1204.   if(!(source=fopen(file,"rb"))){
  1205.     printf(err_open_source "\n",file);
  1206.     exit(EXIT_FAILURE);
  1207.   }
  1208.   pos=0;
  1209. #ifdef AMIGA
  1210.   if((name=strrchr(file,'/')) || (pos=strrchr(file,':')))
  1211.     if(pos)
  1212.       name=pos+1;
  1213.     else
  1214.       name++;
  1215. #endif
  1216. #ifdef MSDOS
  1217.   if((name=strrchr(file,'\\')) || (pos=strrchr(file,':')))
  1218.     if(pos)
  1219.       name=pos+1;
  1220.     else
  1221.       name++;
  1222. #endif
  1223. #ifdef UNIX
  1224.   if(name=strrchr(file,'/'))
  1225.     name++;
  1226. #endif
  1227.   else
  1228.     name=file;
  1229.   if(!(dfile=malloc(strlen(name)+1))){
  1230.     puts(err_no_mem);
  1231.     fclose(source);
  1232.     exit(EXIT_FAILURE);
  1233.   }
  1234.   strcpy(dfile,name);
  1235.   if(path){
  1236.     if(!(dfd=opendir(path))){
  1237.       puts(err_bad_dest);
  1238.       fclose(source);
  1239.       free(dfile);
  1240.       exit(EXIT_FAILURE);
  1241.     }
  1242.     closedir(dfd);
  1243. #ifndef UNIX
  1244.     if(i=strlen(path)){
  1245. #ifdef AMIGA
  1246.       if(path[--i]=='/' || path[i]==':')
  1247.     j=0;
  1248. #else
  1249.       if(path[--i]=='\\' || path[i]==':')
  1250.     j=0;
  1251. #endif
  1252.       else
  1253.     j=1;
  1254.     }
  1255.     else
  1256.       j=0;
  1257.     if(!(dpath=(char *)malloc(strlen(path)+j+1))){
  1258.       puts(err_no_mem);
  1259.       fclose(source);
  1260.       free(dfile);
  1261.       exit(EXIT_FAILURE);
  1262.     }
  1263. #ifdef AMIGA
  1264.     sprintf(dpath,"%s%s",path,j?"/":"");
  1265. #else
  1266.     sprintf(dpath,"%s%s",path,j?"\\":"");
  1267. #endif
  1268. #else
  1269.     if(!(dpath=(char *)malloc(strlen(path)+2))){
  1270.       puts(err_no_mem);
  1271.       fclose(source);
  1272.       free(dfile);
  1273.       exit(EXIT_FAILURE);
  1274.     }
  1275.     sprintf(dpath,"%s/",path);
  1276. #endif
  1277.   }
  1278.   else{
  1279.     if(!(dpath=malloc(name-file+1))){
  1280.       puts(err_no_mem);
  1281.       fclose(source);
  1282.       free(dfile);
  1283.       exit(EXIT_FAILURE);
  1284.     }
  1285.     sprintf(dpath,"%.*s",name-file,file);
  1286.   }
  1287.   if(msdos){
  1288.     if(pos=strchr(dfile,'.'))
  1289.       pos[0]='\0';
  1290.     if(strlen(dfile)>8)
  1291.       dfile[8]='\0';
  1292.   }
  1293.   if(head)
  1294.     sprintf(hd.name,"%.*s",hd_namesize-1,name);
  1295.   if(!(dbuf=(char *)malloc(strlen(dpath)+strlen(dfile)+5))){
  1296.     puts(err_no_mem);
  1297.     fclose(source);
  1298.     free(dfile);
  1299.     free(dpath);
  1300.     exit(EXIT_FAILURE);
  1301.   }
  1302.   if(fseek(source,0L,SEEK_END)){
  1303.     puts(err_seek);
  1304.     fclose(source);
  1305.     free(dfile);
  1306.     free(dpath);
  1307.     free(dbuf);
  1308.     exit(EXIT_FAILURE);
  1309.   }
  1310.   if(!(tsize=ftell(source))){
  1311.     puts(err_file_empty);
  1312.     fclose(source);
  1313.     free(dfile);
  1314.     free(dpath);
  1315.     free(dbuf);
  1316.     exit(EXIT_FAILURE);
  1317.   }
  1318.   if(size){
  1319.     num=(tsize+size-1)/size;
  1320.     size=size<tsize?size:tsize;
  1321.   }
  1322.   else
  1323.     size=(tsize+num-1)/num;
  1324.   if(head){
  1325.     hd.tsize=tsize;
  1326.     hd.tnumber=num;
  1327.   }
  1328.   if(!(tbuf=(char *)malloc(csize=size))){
  1329.     while(csize>10000 && !tbuf)
  1330.       tbuf=(char *)malloc(csize=(csize+1)/2);
  1331.     if(!tbuf){
  1332.       puts(err_no_mem);
  1333.       fclose(source);
  1334.       free(dfile);
  1335.       free(dpath);
  1336.       free(dbuf);
  1337.       exit(EXIT_FAILURE);
  1338.     }
  1339.   }
  1340.   cnum=(size+csize-1)/csize;
  1341.   if(rstart){
  1342.     i=rstart;
  1343.     if(!rend)
  1344.       rend=rstart;
  1345.     if(rend>num || rstart>rend){
  1346.       puts(err_bad_range);
  1347.       fclose(source);
  1348.       free(dfile);
  1349.       free(dpath);
  1350.       free(dbuf);
  1351.       free(tbuf);
  1352.       exit(EXIT_FAILURE);
  1353.     }
  1354.   }
  1355.   else{
  1356.     i=1;
  1357.     rend=num;
  1358.   }
  1359.   if(fseek(source,(i-1)*size,SEEK_SET)){
  1360.     puts(err_seek);
  1361.     fclose(source);
  1362.     free(dfile);
  1363.     free(dpath);
  1364.     free(dbuf);
  1365.     free(tbuf);
  1366.     exit(EXIT_FAILURE);
  1367.   }
  1368.   for(rsize=tsize+(2-i)*size;i<=rend;i++){
  1369.     rsize-=size;
  1370.     asize=(rsize<size?rsize:size);
  1371.     if(head){
  1372.       hd.number=i;
  1373.       hd.size=asize;
  1374.     }
  1375.     sprintf(dbuf,"%s%s.%03d",dpath,dfile,i);
  1376.     if(query && (dest=fopen(dbuf,"rb"))){
  1377.       fclose(dest);
  1378.       printf(query_overwrite_a,dbuf);
  1379.       gets(buf);
  1380.       if(buf[0]==query_all)
  1381.     query=0;
  1382.       else if(buf[0]!=query_yes){
  1383.     puts(err_write_abort);
  1384.     fclose(source);
  1385.     free(dfile);
  1386.     free(dpath);
  1387.     free(dbuf);
  1388.     free(tbuf);
  1389.     exit(EXIT_FAILURE);
  1390.       }
  1391.     }
  1392.     if(multi){
  1393.       puts(make_multi_part);
  1394.       gets(buf);
  1395.     }
  1396.     if(!(dest=fopen(dbuf,"wb"))){
  1397.       printf(err_open_dest "\n",dbuf);
  1398.       fclose(source);
  1399.       free(dfile);
  1400.       free(dpath);
  1401.       free(dbuf);
  1402.       free(tbuf);
  1403.       exit(EXIT_FAILURE);
  1404.     }
  1405.     if(head && WriteHead(dest,&hd)){
  1406.       puts(err_write_head);
  1407.       fclose(dest);
  1408.       fclose(source);
  1409.       free(dfile);
  1410.       free(dpath);
  1411.       free(dbuf);
  1412.       free(tbuf);
  1413.       exit(EXIT_FAILURE);
  1414.     }
  1415.     for(rcsize=asize+csize,j=0;j<cnum;j++){
  1416.       rcsize-=csize;
  1417.       acsize=(rcsize<csize?rcsize:csize);
  1418.       if(fread(tbuf,1,acsize,source)!=acsize){
  1419.     puts(err_read);
  1420.     fclose(dest);
  1421.     fclose(source);
  1422.     free(dfile);
  1423.     free(dpath);
  1424.     free(dbuf);
  1425.     free(tbuf);
  1426.     exit(EXIT_FAILURE);
  1427.       }
  1428.       if(fwrite(tbuf,1,acsize,dest)!=acsize){
  1429.     puts(err_write);
  1430.     fclose(dest);
  1431.     fclose(source);
  1432.     free(dfile);
  1433.     free(dpath);
  1434.     free(dbuf);
  1435.     free(tbuf);
  1436.     exit(EXIT_FAILURE);
  1437.       }
  1438.     }
  1439.     fclose(dest);
  1440.   }
  1441.   fclose(source);
  1442.   free(tbuf);
  1443.   free(dbuf);
  1444.   free(dpath);
  1445.   free(dfile);
  1446.   i=head?hd_size:0;
  1447.   printf(split_Splitted,file);
  1448.   if(num-1)
  1449.     if(num*size==tsize)
  1450.       printf(split_portions "\n",num,size+i);
  1451.     else
  1452.       if(num-2)
  1453.     printf(split_portions_and "\n",num-1,size+i,rsize+i);
  1454.       else
  1455.     printf(split_portion_and "\n",size+i,rsize+i);
  1456.   else
  1457.     printf(split_portion "\n",rsize+i);
  1458.   if(rstart)
  1459.     if(rstart!=rend)
  1460.       printf(split_Extract "\n",rstart,rend);
  1461.     else
  1462.       printf(split_Extract_one "\n",rstart);
  1463.   exit(0);
  1464. }
  1465.  
  1466. /*
  1467.   main(int argc,char *argv[])
  1468.     argc:     Number of arguments.
  1469.     argv:     Array of arguments.
  1470.   Global:
  1471.     msdos:    -set-  Filenames use msdos compatible format.
  1472.     head:     -set-  Use headers.
  1473.     multi:    -set-  Use multiple volumes.
  1474.     query:    -set-  Ask before overwriting existing file.
  1475.     rstart:   -set-  First protion to extract.   
  1476.     rend:     -set-  Last Portion to extract.
  1477.   Calls:
  1478.     Split:    Split a file.
  1479.     Join:     Join splitted parts.
  1480.   In main() the arguments are parsed and the appropriate functions
  1481.   are called. When calling Join(), 'paths' is not freed.
  1482. */
  1483. void main(int argc,char **argv)
  1484. {
  1485.   int i,j,action,pathnum,portnum,defj;
  1486.   unsigned long portsize;
  1487.   char *arg,*path,*file,**paths;
  1488. #ifdef DBUG
  1489.   printf("\nmain(%d,({",argc);
  1490.   for(i=0;i<argc-1;i++)
  1491.     printf("\"%s\",",argv[i]);
  1492.   printf("\"%s\"",argv[i]);
  1493.   puts("}));");
  1494. #endif
  1495.   if(argc==1){
  1496.     printf(err_no_args "\n",argv[0]);
  1497.     exit(EXIT_FAILURE);
  1498.   }
  1499.   if(!(paths=(char **)malloc((argc-1)*sizeof(char *)))){
  1500.     puts(err_no_mem);
  1501.     exit(EXIT_FAILURE);
  1502.   }
  1503. #ifdef MSDOS
  1504.   msdos=1;
  1505. #else
  1506.   msdos=0;
  1507. #endif
  1508.   pathnum=rstart=rend=portnum=0;
  1509.   portsize=0;
  1510.   head=1;
  1511. #if FORCE
  1512.   query=0;
  1513. #else
  1514.   query=1;
  1515. #endif
  1516.   if(strstr(argv[0],"Join") || strstr(argv[0],"join"))
  1517.     action=defj=1;
  1518.   else
  1519.     action=defj=0;
  1520.   if(strchr(argv[0],'M') || strchr(argv[0],'m'))
  1521.     multi=1;
  1522.   else
  1523.     multi=0;
  1524.   for(i=1;i<argc;i++){
  1525.     arg=argv[i];
  1526.     if('-'==*arg)
  1527.       while(*++arg)
  1528.     switch(*arg){
  1529.     case 'h':
  1530.       if(defj)
  1531.         printf(info1j,argv[0]);
  1532.       else{
  1533.         printf(info1s,argv[0]);
  1534.         getchar();
  1535.         puts(info2);
  1536.         for(j=0;j<sizeof(fs)/sizeof(struct fs_item);j++)
  1537.           printf(main_fs "\n",fs[j].name,fs[j].size,fs[j].desc);
  1538.       }
  1539.       puts(main_end);
  1540.       free(paths);
  1541.       exit(0);
  1542.     case 'j':
  1543.       action=1;
  1544.       break;
  1545.     case 's':
  1546.       action=2;
  1547.       if(!*++arg){
  1548.         if(i==argc-1){
  1549.           puts(err_bad_size);
  1550.           free(paths);
  1551.           exit(EXIT_FAILURE);
  1552.         }
  1553.         arg=argv[++i];
  1554.       }
  1555.       for(j=0;j<sizeof(fs)/sizeof(struct fs_item);j++)
  1556.         if(!strcmp(arg,fs[j].name))
  1557.           portsize=fs[j].size;
  1558.       if(!portsize){
  1559.         if(!(portsize=atol(arg))){
  1560.           puts(err_bad_size);
  1561.           free(paths);
  1562.           exit(EXIT_FAILURE);
  1563.         }
  1564.         if(strchr(arg,'k'))
  1565.           portsize*=1024;
  1566.         if(strchr(arg,'m'))
  1567.           portsize*=1024*1024;
  1568.       }
  1569.       *arg--=0;
  1570.       break;
  1571.     case 'p':
  1572.       action=3;
  1573.       if(!*++arg){
  1574.         if(i==argc-1){
  1575.           puts(err_bad_num);
  1576.           free(paths);
  1577.           exit(EXIT_FAILURE);
  1578.         }
  1579.         arg=argv[++i];
  1580.       }
  1581.       if(!(portnum=atoi(arg))){
  1582.         puts(err_bad_num);
  1583.         free(paths);
  1584.         exit(EXIT_FAILURE);
  1585.       }
  1586.       *arg--=0;
  1587.       break;
  1588.     case 'r':
  1589.       if(!*++arg){
  1590.         if(i==argc-1){
  1591.           puts(err_bad_range);
  1592.           free(paths);
  1593.           exit(EXIT_FAILURE);
  1594.         }
  1595.         arg=argv[++i];
  1596.       }
  1597.       if(!(rstart=atoi(arg))){
  1598.         puts(err_bad_range);
  1599.         free(paths);
  1600.         exit(EXIT_FAILURE);
  1601.       }
  1602.       if(i<argc-1 && !(rend=atoi(argv[++i])))
  1603.         --i;
  1604.       *arg--=0;
  1605.       break;
  1606.     case 'd':
  1607.       msdos=1;
  1608.       break;
  1609.     case 'l':
  1610.       msdos=0;
  1611.       break;
  1612.     case 'n':
  1613.       head=0;
  1614.       break;
  1615.     case 'm':
  1616.       multi=1;
  1617.       break;
  1618.     case 'g':
  1619.       multi=0;
  1620.       break;
  1621.     case 'f':
  1622.       query=0;
  1623.       break;
  1624.     case 'q':
  1625.       query=1;
  1626.       break;
  1627.     default:
  1628.       printf(err_unknown_option "\n",*arg);
  1629.       free(paths);
  1630.       exit(EXIT_FAILURE);
  1631.     }
  1632.     else
  1633.       paths[pathnum++]=arg;
  1634.   }
  1635.   if(!pathnum--){
  1636.     puts(err_no_file);
  1637.     free(paths);
  1638.     exit(EXIT_FAILURE);
  1639.   }
  1640.   if(action!=1){
  1641.     file=paths[0];
  1642.     if(pathnum)
  1643.       path=paths[1];
  1644.     else
  1645.       path=0;
  1646.     free(paths);
  1647.   }
  1648.   switch(action){
  1649.   case 1:
  1650.     Join(paths[pathnum],paths,pathnum);
  1651.   case 2:
  1652.     Split(file,path,0,portsize);
  1653.   case 3:
  1654.     Split(file,path,portnum,0);
  1655.   default:
  1656.     Split(file,path,0,fs[0].size);
  1657.   }
  1658. }
  1659.